/*--------------------------------------------------------------------------
	@class sci.quadrant.CanvasController
	@author Eduardo Echeverria
	@version 1.0 February 4, 2014
	@description
  --------------------------------------------------------------------------
*/
sci.Require('sci.quadrant.QuadrantViewModel');
sci.Provide('sci.quadrant.CanvasController');

//-- Public Constructor -----------------------------------------------------
sci.quadrant.CanvasController = function (view, viewModel) {
    if (!view)
        throw 'sci.quadrant.CanvasController :: A view is required';

    this.View = view;
    this.View.style.clip = 'rect(0px ' + this.View.clientWidth + 'px ' + this.View.clientHeight + 'px 0px)'; /*Top Right Bottom Left*/

    this.ViewModel = null;
    this.ImageFolder = this.View.getAttribute('data-image-folder');

    var imageFileExtension = this.View.getAttribute('data-image-file-extension');
    this.TileFileExtension = imageFileExtension ? imageFileExtension : '.jpg';

    this.BlockSide = 128;
    this.ColumnCount = 1;
    this.RowCount = 1;


    this.PreviousX = 0;
    this.PreviousY = 0;
    this.ConstantList = '';


    this.Canvas = document.createElement('div');
    this.Canvas.style.position = 'absolute';
    this.Canvas.style.width = (this.View.clientWidth + this.BlockSide) + 'px';
    this.Canvas.style.height = (this.View.clientHeight + this.BlockSide) + 'px';
    this.View.appendChild(this.Canvas);

    this.Blocks = new Array();
    this.ViewModelColumns = 1;
    this.ViewModelRows = 1;
    this.Index = 0;

    this.LimitTop = 0;
    this.LimitBottom = this.View.clientWidth + this.BlockSide;
    this.LimitLeft = 0;
    this.LimitRight = this.View.clientHeight + this.BlockSide;

    if (viewModel)
        this.SetViewModel(viewModel);
};

//-- Public Methods ---------------------------------------------------------
/*--------------------------------------------------------------------------
	@method removeObserver
	@param 
	@description 
  --------------------------------------------------------------------------
*/
sci.quadrant.CanvasController.prototype.GetView = function () {
    return this.View;
};

sci.quadrant.CanvasController.prototype.GetViewModel = function () {
    return this.ViewModel;
};

sci.quadrant.CanvasController.prototype.SetViewModel = function (viewModel) {
    if (this.ViewModel) {
        this.ViewModel.RemoveObserver('ContentUpdate', this);
        this.ViewModel.RemoveObserver('LocationChanged', this);
        this.ViewModel.RemoveObserver('SizeChange', this);
    }

    this.ViewModel = viewModel;

    if (this.ViewModel) {
        this.ViewModel.AddObserver('ContentUpdate', this, 'ViewModel_ContentUpdate');
        this.ViewModel.AddObserver('LocationChange', this, 'ViewModel_LocationChange');
        this.ViewModel.AddObserver('SizeChange', this, 'ViewModel_SizeChange');

        this.InitializeCanvas(this.View.clientWidth, this.View.clientHeight);
    }
};

sci.quadrant.CanvasController.prototype.InitializeCanvas = function (w, h) {
    if (this.ViewModel.GetWidth() <= w) {
        w = (this.ViewModel.GetWidth() - 1);
        this.View.style.width = w + 'px';
    }

    if (this.ViewModel.GetHeight() <= h) {
        h = this.ViewModel.GetHeight() - 1;
        this.View.style.height = h + 'px';
    }

    this.LimitRight = this.ViewModel.GetWidth() - w;
    this.LimitBottom = this.ViewModel.GetHeight() - this.View.clientHeight;
    this.InitializeViewModelColumnsAndRows(this.ViewModel.GetWidth(), this.ViewModel.GetHeight());
    this.InitializeColumnsAndRows(w, h);
    this.InitializeBlocks();
    this.LoadBlocks();
};

sci.quadrant.CanvasController.prototype.InitializeViewModelColumnsAndRows = function (w, h) {
    this.ViewModelColumns = Math.ceil(w / this.BlockSide);
    this.ViewModelRows = Math.ceil(h / this.BlockSide);
}

sci.quadrant.CanvasController.prototype.InitializeColumnsAndRows = function (w, h) {
    this.Columns = Math.ceil(w / this.BlockSide) + 1;
    this.Rows = Math.ceil(h / this.BlockSide) + 1;
};

sci.quadrant.CanvasController.prototype.InitializeBlocks = function () {
        var blockCount = this.Columns * this.Rows;
        var difference = blockCount - this.Blocks.length;

        if (difference < 0) {
            alert('TODO: Remove Blocks (MapController.initBlocks)');
        }
        else if (difference > 0) {
            var current = 0;

            for (var i = 0; i < this.Rows; i++) {
                for (var j = 0; j < this.Columns; j++) {
                    if (current < this.Blocks.length) {
                        var block = this.Blocks[current];
                        block.style.left = j * this.BlockSide;
                        block.style.top = i * this.BlockSide;
                    }
                    else { this.AddBlock(j * this.BlockSide, i * this.BlockSide); }

                    current++;
                }
            }
        }
};

sci.quadrant.CanvasController.prototype.LoadBlocks = function () {
    var index = this.Index;
    var leap = this.ViewModelColumns - this.Columns;
    var currentColumn = 0;

    for (var i = 0; i < this.Blocks.length; i++) {
        index++;
        currentColumn++;

        if (this.ConstantList.indexOf(',' + i + ',') == -1) {
            this.Blocks[i].style.visibility = 'hidden';
            this.Blocks[i].src = this.ImageFolder + this.ViewModel.GetImage() + index + this.TileFileExtension;
        }

        if (currentColumn == this.Columns) {
            currentColumn = 0;
            index += leap;
        }
    }

    this.ConstantList = '';
};

sci.quadrant.CanvasController.prototype.AddBlock = function (x, y) {
    var block = document.createElement('img');
    block.style.width = this.BlockSide + 'px';
    block.style.height = this.BlockSide + 'px';
    block.style.position = 'absolute';
    block.style.left = x + 'px';
    block.style.top = y + 'px';
    block.onload = function () { this.style.visibility = 'visible'; };
    this.Blocks.push(block);
    this.Canvas.appendChild(block);
}

//sci.quadrant.CanvasController.prototype.View_Resize = function (w, h) {
//    this.InitializeCanvas(w, h);
//}

sci.quadrant.CanvasController.prototype.ViewModel_ContentUpdate = function (e) {
    this.InitializeCanvas(this.View.clientWidth, this.View.clientHeight);
    this.PreviousX = 0;
    this.PreviousY = 0;
    this.Index = 0;
    this.ConstantList = '';
    this.LoadBlocks();
};

sci.quadrant.CanvasController.prototype.ViewModel_SizeChange = function (e) {
    this.InitializeCanvas(this.View.clientWidth, this.View.clientHeight);
    this.PreviousX = this.Columns;
    this.PreviousY = this.Rows;
    this.Index = 0;
    this.ConstantList = '';
    this.LoadBlocks();
};

sci.quadrant.CanvasController.prototype.ViewModel_LocationChange = function (e) {
    this.ConstantList = ',';
    //showRed = true;

    var x = e.X;
    if (x < this.LimitLeft) { x = this.LimitLeft; }
    else if (x > this.LimitRight) { x = this.LimitRight; }

    var c = Math.floor(x / this.BlockSide);
    var xDif = c - this.PreviousX;
    x = x % this.BlockSide;

    var y = e.Y;
    if (y < this.LimitTop) { y = this.LimitTop; }
    else if (y > this.LimitBottom) { y = this.LimitBottom; }

    var r = Math.floor(y / this.BlockSide);
    var yDif = r - this.PreviousY;
    y = y % this.BlockSide;


    if (Math.abs(yDif) < this.Rows && Math.abs(xDif) < this.Columns && (xDif + yDif) != 0) {
        var down = yDif < 0;
        var right = xDif < 0;
        var rEnd = (down) ? (yDif + this.Rows) * this.Columns : yDif * this.Columns;
        for (var i = 0; i < rEnd; i++) { this.Blocks.push(this.Blocks.shift()); }

        if (right) { xDif += this.Columns; }
        var cStart = (down) ? this.Blocks.length - rEnd : 0;
        var cEnd = (down) ? this.Blocks.length : this.Blocks.length - rEnd;
        var p1 = cStart + xDif;
        var p3 = cStart + this.Columns - 1;
        var p2 = p3 - xDif;
        var temp = new Array();

        for (var i = cStart; i < cEnd; i++) {
            if (i < p1) {
                temp.push(this.Blocks[i]);

            }
            else {
                this.Blocks[i - xDif] = this.Blocks[i];
                if (!right) { this.ConstantList += (i - xDif) + ','; }
            }

            if (i > p2) {
                this.Blocks[i] = temp.shift();
                if (right) { this.ConstantList += i + ','; }
            }

            if (i == p3) {
                p1 += this.Columns;
                p2 += this.Columns;
                p3 += this.Columns;
            }
        }
    }
    else { /*alert('UPDATE ALL');*/ }

    this.PreviousY = r;
    this.PreviousX = c;

    var current = 0;

    for (var i = 0; i < this.Rows; i++) {
        for (var j = 0; j < this.Columns; j++) {
            this.Blocks[current].style.left = parseFloat(j * this.BlockSide - x) + 'px';
            this.Blocks[current].style.top = parseFloat(i * this.BlockSide - y) + 'px';
            current++;
        }
    }

    var ix = this.ViewModelColumns * this.PreviousY + this.PreviousX;

    if (this.Index === ix)
        return;

    this.Index = ix;
    this.LoadBlocks();
};

sci.quadrant.CanvasController.prototype.toString = function () {
    return '[Object:sci.quadrant.CanvasController]';
};

sci.Ready('sci.quadrant.CanvasController');